package com.sunyard.manage.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.sunyard.constant.ErrMessageConst;
import com.sunyard.constant.StatusConstant;
import com.sunyard.constant.manage.StatusConstants;
import com.sunyard.dal.bo.operator.OperatorAuditBO;
import com.sunyard.dal.bo.operator.OperatorAuditChangeQueryBO;
import com.sunyard.dal.bo.operator.OperatorAuditQueryBO;
import com.sunyard.dal.bo.PaginationBO;
import com.sunyard.dal.bo.task.TaskFindBO;
import com.sunyard.dal.dto.OperatorCopyDTO;
import com.sunyard.dal.dto.OperatorCopyExportDTO;
import com.sunyard.dal.dto.OperatorDTO;
import com.sunyard.dal.dto.znsTask.TaskZNSDTO;
import com.sunyard.dal.entity.*;
import com.sunyard.dal.mapper.*;
import com.sunyard.enums.TerminalTypeEnum;
import com.sunyard.manage.constant.TblLogConst;
import com.sunyard.manage.service.OperatorAuditService;
import com.sunyard.manage.service.OperatorLogService;
import com.sunyard.redisUtil.RedisUtils;
import com.sunyard.utils.DtoUtils;
import com.sunyard.utils.ExcelOutput;
import com.sunyard.utils.Response.BaseResult;
import com.sunyard.utils.Response.GetResult;
import com.sunyard.utils.Response.HeaderResult;
import com.sunyard.utils.TokenUtil;
import com.sunyard.utils.manage.DataGrid;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.OutputStream;
import java.util.*;
import java.util.stream.Collectors;

import static java.util.stream.Collectors.toList;

/**
 * @author jiy.fang
 * @ClassName OperatorAuditServiceImpl
 * @Description description
 * @date 2019/7/25 10:03
 */
@Service
@Slf4j
public class OperatorAuditServiceImpl implements OperatorAuditService {

    @Autowired
    private OperatorCopyMapper operatorCopyMapper;

    @Autowired
    private OperatorMapper operatorMapper;

    @Autowired
    private OperatorLogService operatorLogService;

    @Autowired
    private OrganizationMapper organizationMapper;

    @Autowired
    private RedisUtils redisUtils;

    @Autowired
    private RoleMapper roleMapper;

    @Autowired
    private TerminalMapper terminalMapper;

    @Autowired
    private TaskMapper taskMapper;

    @Autowired
    private ZNSTaskMapper znsTaskMapper;

    @Autowired
    private BulletinMapper bulletinMapper;

    @Autowired
    private BulletinRelMapper bulletinRelMapper;

    /**
     * 初始密码
     */
    @Value("${init.pwd}")
    private String initPwd;

    @Autowired
    private ValueOperations<String, String> valueOperations;


    /**
     * @Description: 分页查询用户审核信息
     * @Author: jiy.fang
     * @Date: 2019/7/25 10:08
     */
    @Override
    public DataGrid<OperatorCopyDTO> queryOperatorListAuditByPage(HttpServletRequest request, PaginationBO<OperatorAuditQueryBO> queryBO) {
        OperatorAuditQueryBO operatorAuditQueryBO = queryBO.getParams();
        log.info("用户审核查询入参：{}", JSON.toJSONString(operatorAuditQueryBO));
        String orgId = TokenUtil.getOrgId(request.getHeader("token"));
        if (StringUtils.isNotBlank(operatorAuditQueryBO.getOrgId())) {
            orgId = operatorAuditQueryBO.getOrgId();
        }
        Map<String, Object> queryMap = new HashMap<>();
        queryMap.put("orgId", orgId);
        queryMap.put("opName", operatorAuditQueryBO.getOpName());
        queryMap.put("opRealname", operatorAuditQueryBO.getOpRealname());
        queryMap.put("roleId", operatorAuditQueryBO.getRoleId());
        queryMap.put("roleName", operatorAuditQueryBO.getRoleName());
        queryMap.put("auditFlag", operatorAuditQueryBO.getAuditFlag());
        queryMap.put("auditType", operatorAuditQueryBO.getAuditType());
        queryMap.put("includeSubOrg", operatorAuditQueryBO.getIncludeSubOrg());
        queryMap.put("opId", operatorAuditQueryBO.getOpId());
        List<String> orgIds = new ArrayList<>();
        //获取当前机构及下属机构id集合
        if (operatorAuditQueryBO.getOrgId() == null || "".equals(operatorAuditQueryBO.getOrgId())) {
            orgIds = getListOrgIds(orgId);
            orgIds.add(orgId);
            queryMap.put("list", orgIds);
        } else {
            orgIds.add(operatorAuditQueryBO.getOrgId());
            queryMap.put("list", orgIds);
        }
        //设置分页信息
        PageHelper.startPage(queryBO.getPageNo(), queryBO.getPageSize());
        //执行查询
        List<OperatorCopyDTO> list = operatorCopyMapper.getOperatorCopyListByPage(queryMap);
        //取分页信息
        PageInfo<OperatorCopyDTO> pageInfo = new PageInfo<>(list);
        //设置返回结果
        DataGrid<OperatorCopyDTO> dataGrid = new DataGrid<>();
        Long total = pageInfo.getTotal();
        dataGrid.setTotal(total.intValue());
        dataGrid.setRows(list);
        return dataGrid;
    }

    @Override
    public void operatorAuditExport(HttpServletResponse response, OperatorAuditQueryBO operatorAuditQueryBO, HttpServletRequest request) {
        try {
            String opId = TokenUtil.getOpId(request.getHeader("token"));
            String orgId = TokenUtil.getOrgId(request.getHeader("token"));
            String opName = TokenUtil.getOpName(request.getHeader("token"));
            operatorLogService.insert("用户审核导出", "用户审核导出", "1", opId, opName, orgId);
            // 执行查询
            //获取当前机构及下属机构id集合
            List<String> orgIds = new ArrayList<>();
            if (StringUtils.isBlank(operatorAuditQueryBO.getOrgId())) {
                orgIds = getListOrgIds(orgId);
                orgIds.add(orgId);
                operatorAuditQueryBO.setOrgIds(orgIds);
            } else {
                orgIds.add(operatorAuditQueryBO.getOrgId());
                operatorAuditQueryBO.setOrgIds(orgIds);
            }
            List<OperatorCopyExportDTO> list = operatorCopyMapper.operatorAuditExport(operatorAuditQueryBO);
            if (list == null || list.isEmpty()) {
                throw new RuntimeException("无数据无需导出");
            }
            String title = "用户审核导出" + Math.random() + ".xls";
            String[] headers = new String[]{"审核流水号", "审核操作", "审核状态", "用户编号", "用户名", "申请日期","申请人", "审核人", "审核理由"};

            List<Object[]> dataList;
            dataList = list.stream().map(operatorCopy -> {
                Object[] obj = new Object[headers.length];
                obj[0] = operatorCopy.getAuditId();
                obj[1] = operatorCopy.getAuditType();
                obj[2] = operatorCopy.getAuditFlag();
                obj[3] = operatorCopy.getOpName();
                obj[4] = operatorCopy.getOpRealname();
                obj[5] = operatorCopy.getCreateTime();
                obj[6] = operatorCopy.getCreateOp();
                obj[7] = operatorCopy.getAuditOp();
                obj[8] = operatorCopy.getOpRemark();
                return obj;
            }).collect(toList());
            OutputStream out = null;
            // 防止中文乱码
            String headStr = "attachment; filename=\"" + new String(title.getBytes("gb2312"), "ISO8859-1") + "\"";
            response.setContentType("octets/stream");
            response.setContentType("APPLICATION/OCTET-STREAM");
            response.setHeader("Content-Disposition", headStr);
            out = response.getOutputStream();
            ExcelOutput ex = new ExcelOutput(title, headers, dataList);
            ex.export(out);
            log.info("用户审核导出");
        } catch (Exception e) {
            log.error(ErrMessageConst.SYSTEM_ERROR, e);
            HeaderResult.setFailHeader(request, response, e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResult operatorAudit(HttpServletRequest request, OperatorAuditBO operatorAuditBO) throws Exception {
        String opId = TokenUtil.getOpId(request.getHeader("token"));
        String orgId = TokenUtil.getOrgId(request.getHeader("token"));
        String opName = TokenUtil.getOpName(request.getHeader("token"));
        //判断审核操作是否符合条件
        OperatorCopy operatorCopy = operatorCopyMapper.getOperatorCopyByAuditId(operatorAuditBO.getAuditId());
        Operator operatorByOpId = operatorMapper.getOperatorByOpId(operatorCopy.getOpId());
        if (Objects.isNull(operatorCopy)) {
            return GetResult.getResultFail("该审核记录不存在！");
        }
        if (!StatusConstant.AUDIT_FLAG_DEFAULT.equals(operatorCopy.getAuditFlag())) {
            return GetResult.getResultFail("该审核记录已审核！");
        }
        //判断当前登录用户是否是指定审核人
        if (!opId.equals(operatorCopy.getAuditor())) {
            return GetResult.getResultFail("当前用户没有审核权限！");
        }
        //如果审核结果为不通过，直接返回
        if (StatusConstant.AUDIT_FLAG_FAIL.equals(operatorAuditBO.getAuditFlag()) || StatusConstant.AUDIT_FLAG_DEFAULT.equals(operatorAuditBO.getAuditFlag())) {
            if (operatorCopy.getAuditType() != 0){
                Operator operator = operatorMapper.getOperatorByOpId(operatorCopy.getOpId());
                operator.setAuditStatus("0");
                operatorMapper.updateOperatorAuditStatus(operator);
            }
            //修改审核记录表
            operatorCopy.setAuditOp(opId);
            operatorCopy.setAuditFlag(operatorAuditBO.getAuditFlag());
            operatorCopy.setAuditDesc(operatorAuditBO.getAuditDesc());
            operatorCopyMapper.updateOperatorCopy(operatorCopy);
            String auditFlagCopy = "审核未通过";
            String operationDescCopy = "用户：" + opName + " 审核了ID：" + operatorAuditBO.getAuditId() + "的数据，结果：" + auditFlagCopy;
            addLogMessage(opId, opName, operationDescCopy, TblLogConst.OPERATOR_UPDATE_AUDIT, orgId);
            return GetResult.getResultSuccess("审核成功！");
        }
        Organization organization = organizationMapper.getOrganizationByOrgId(operatorCopy.getOrgId());
        if (ObjectUtil.isNull(organization)){
            return GetResult.getResultFail("用户" + operatorCopy.getOpName() + "所属机构不存在，无法审核");
        }
        Role role = roleMapper.getRoleByRoleId(operatorCopy.getRoleId());
        if (ObjectUtil.isNull(role)){
            return GetResult.getResultFail("用户" + operatorCopy.getOpName() + "所属角色不存在，无法审核");
        }
        //日志描述
        String auditFlag = "审核通过";
        String operationDesc = "用户：" + opName + " 审核了ID：" + operatorAuditBO.getAuditId() + "的数据，结果：" + auditFlag;
        //修改审核记录表
        operatorCopy.setAuditOp(opId);
        operatorCopy.setAuditFlag(operatorAuditBO.getAuditFlag());
        operatorCopy.setAuditDesc(operatorAuditBO.getAuditDesc());
        operatorCopyMapper.updateOperatorCopy(operatorCopy);
        //修改用户主表信息
        Operator operator1 = new Operator();
        DtoUtils.cloneBeanToBean(operator1, operatorCopy);
        String logName = "";
        if (StatusConstant.AUDIT_TYPE_ADD.equals(operatorCopy.getAuditType())) {
            //是否注销重开
            Operator operator2 = operatorMapper.getOperatorByOpNameString(operator1.getOpName());
            if (Objects.nonNull(operator2)) {
                operator1.setOpId(null);
                operatorMapper.updateOperatorByOpName(operator1);
            } else {
                operatorMapper.insertOperator(operator1);
            }
            List<String> bulletinIdList = bulletinMapper.getBulletinIdList(operator1.getOrgId());
            for (String bulletinId: bulletinIdList) {
                BulletinRel bulletinRel = new BulletinRel();
                bulletinRel.setHasRead("0");
                bulletinRel.setIsDelete("0");
                bulletinRel.setBulletinId(bulletinId);
                bulletinRel.setOpId(operator1.getOpId());
                bulletinRel.setOrgId(operator1.getOrgId());
                bulletinRelMapper.insert(bulletinRel);
            }
            logName = TblLogConst.OPERATOR_ADD_AUDIT;
        } else if (StatusConstant.AUDIT_TYPE_UPDATE.equals(operatorCopy.getAuditType())) {
            //修改用户信息的审核状态 变为已审核
            operator1.setAuditStatus("1");
            operatorMapper.updateOperatorAuditStatus(operator1);
            operatorMapper.updateOperator(operator1);
            //人员调岗或者修改角色 时清空该人员任务和锁具类型清楚人员关联关系
            if (!operatorByOpId.getOrgId().equals(operatorCopy.getOrgId()) || !operatorByOpId.getRoleId().equals(operatorCopy.getRoleId())){
                //删除调拨任务前清除锁具在新机构的有效任务
                resetBrcTask(operatorCopy.getOpName());
                //删除关联任务
                znsTaskMapper.deleteBYOp(operatorCopy.getOpName());
                terminalMapper.updateByAdminId(operatorCopy.getOpId());
            }
            logName = TblLogConst.OPERATOR_UPDATE_AUDIT;
        } else if (StatusConstant.AUDIT_TYPE_DELETE.equals(operatorCopy.getAuditType())) {
            //修改用户信息的审核状态 变为已审核
            operator1.setAuditStatus("1");
            operatorMapper.updateOperatorAuditStatus(operator1);
            operatorMapper.deleteOperator(operator1);
            logName = TblLogConst.OPERATOR_DELETE_AUDIT;
        } else if (StatusConstant.AUDIT_TYPE_RESETPWD.equals(operatorCopy.getAuditType())
                || StatusConstant.AUDIT_TYPE_UNLOCK.equals(operatorCopy.getAuditType())
                || StatusConstant.AUDIT_TYPE_ENABLE.equals(operatorCopy.getAuditType())) {
            operator1.setOpStatus(Integer.parseInt(StatusConstants.OPERATPR_NORMAL));
            //修改用户信息的审核状态 变为已审核
            operator1.setAuditStatus("1");
            operatorMapper.updateOperatorAuditStatus(operator1);
            operatorMapper.updateOperator(operator1);
            if (StatusConstant.AUDIT_TYPE_RESETPWD.equals(operatorCopy.getAuditType())){
                logName = TblLogConst.OPERATOR_RESET_PWD_AUDIT;
            }
            if(StatusConstant.AUDIT_TYPE_UNLOCK.equals(operatorCopy.getAuditType())){
                logName = TblLogConst.OPERATOR_UNLOCK_AUDIT;
            }
            if(StatusConstant.AUDIT_TYPE_ENABLE.equals(operatorCopy.getAuditType())){
                logName = TblLogConst.OPERATOR_ENABLE_AUDIT;
            }
        } else if (StatusConstant.AUDIT_TYPE_DISABLE.equals(operatorCopy.getAuditType())) {
            operator1.setOpStatus(Integer.parseInt(StatusConstants.OPERATPR_DISABLE));
            //修改用户信息的审核状态 变为已审核
            operator1.setAuditStatus("1");
            operatorMapper.updateOperatorAuditStatus(operator1);
            operatorMapper.updateOperator(operator1);
            //异步审核停用用户时同时修改任务状态
            //删除调拨任务前清除锁具在新机构的有效任务
            resetBrcTask(operator1.getOpName());
            //删除关联任务
            znsTaskMapper.deleteBYOp(operator1.getOpName());
            terminalMapper.updateByAdminId(operator1.getOpId());
            logName = TblLogConst.OPERATOR_DISABLE_AUDIT;
        } else {
            return GetResult.getResultFail("该审核记录状态错误！");
        }
        addLogMessage(opId, opName, operationDesc, logName, orgId);
        //强制退出登录
        redisUtils.set(operator1.getOpName(), System.currentTimeMillis());
        return GetResult.getResultSuccess("审核成功！");

    }

    private void addLogMessage(String opId, String opName, String operationDesc, String logName, String orgId) {
        operatorLogService.insert(operationDesc, logName, "1", opId, opName, orgId);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public BaseResult batchOperatorAudit(HttpServletRequest request, OperatorAuditBO auditBO) throws Exception {
        String[] auditIds = auditBO.getAuditId().split(",");
        for (String auditId : auditIds) {
            OperatorAuditBO operatorAuditBO = new OperatorAuditBO();
            BeanUtil.copyProperties(auditBO, operatorAuditBO);
            operatorAuditBO.setAuditId(auditId);
            BaseResult result = operatorAudit(request, operatorAuditBO);
            if (!"00".equals(result.getDataCode())) {
                return GetResult.getResultFail(result.getDataMessage());
            }
        }
        return GetResult.getResultSuccess("审核成功");
    }

    /**
     * @Description: 用户审核信息对比
     * @Author: jiy.fang
     * @Date: 2019/8/2 18:10
     */
    @Override
    public Map<Object, Object> queryOperatorRecordChange(OperatorAuditChangeQueryBO changeQueryBO) {
        OperatorCopyDTO operatorCopyDTO = operatorCopyMapper.getOperatorCopyDTOByAuditId(changeQueryBO.getAuditId());
        OperatorDTO operatorDTO = JSON.parseObject(operatorCopyDTO.getEntityRecord(), OperatorDTO.class);
        Map<Object, Object> operatorComparisonMap = new HashMap<>();
        //  添加用户审核对比
        if (operatorCopyDTO.getAuditType() == 0) {
            operatorComparisonMap.put("operatorAudit", operatorCopyDTO);
        }else if (operatorCopyDTO.getAuditType() == 1) {
            //  用户删除审核对比
            if (operatorCopyDTO.getAuditFlag() == 0) {
                if (ObjectUtil.isNull(operatorDTO)){
                    operatorDTO = new OperatorDTO();
                    Operator operator = operatorMapper.getOperatorByOpId(operatorCopyDTO.getOpId());
                    BeanUtil.copyProperties(operator, operatorDTO);
                    Role role = roleMapper.getRoleByRoleId(operator.getRoleId());
                    if (ObjectUtil.isNotNull(role)) {
                        operatorDTO.setRoleName(role.getRoleName());
                    }
                    Organization organization = organizationMapper.getOrganizationByOrgId(operator.getOrgId());
                    if (ObjectUtil.isNotNull(organization)) {
                        operatorDTO.setOrgName(organization.getOrgName());
                    }
                    operatorComparisonMap.put("operator", operatorDTO);
                }else {
                    operatorComparisonMap.put("operator", operatorDTO);
                }
            }
            if (operatorCopyDTO.getAuditFlag() == 1) {
                operatorComparisonMap.put("operator", operatorCopyDTO);
            }
            if (operatorCopyDTO.getAuditFlag() == 2) {
                if (ObjectUtil.isNull(operatorDTO)){
                    operatorDTO = new OperatorDTO();
                    Operator operator = operatorMapper.getOperatorByOpId(operatorCopyDTO.getOpId());
                    BeanUtil.copyProperties(operator, operatorDTO);
                    Role role = roleMapper.getRoleByRoleId(operator.getRoleId());
                    if (ObjectUtil.isNotNull(role)) {
                        operatorDTO.setRoleName(role.getRoleName());
                    }
                    Organization organization = organizationMapper.getOrganizationByOrgId(operator.getOrgId());
                    if (ObjectUtil.isNotNull(organization)) {
                        operatorDTO.setOrgName(organization.getOrgName());
                    }
                    operatorComparisonMap.put("operator", operatorDTO);
                }else {
                    operatorComparisonMap.put("operator", operatorDTO);
                }
            }
        }else {
            operatorComparisonMap.put("operatorAudit", operatorCopyDTO);
            operatorComparisonMap.put("operator", operatorDTO);
        }
        //  用户修改审核对比
        // if (operatorCopyDTO.getAuditType() == 2 || operatorCopyDTO.getAuditType() == 3 || operatorCopyDTO.getAuditType() == 4 || operatorCopyDTO.getAuditType() == 5 || operatorCopyDTO.getAuditType() == 6) {
        //     operatorComparisonMap.put("operatorAudit", operatorCopyDTO);
        //     operatorComparisonMap.put("operator", operatorDTO);
        // }
        //  用户状态的改变
        // if (operatorCopyDTO.getAuditType() == 3 || operatorCopyDTO.getAuditType() == 4 || operatorCopyDTO.getAuditType() == 5 || operatorCopyDTO.getAuditType() == 6) {
        //     operatorComparisonMap.put("operatorAudit", operatorCopyDTO);
        //     operatorComparisonMap.put("operator", operatorDTO);
        // }
        return operatorComparisonMap;
    }

    /**
     * @Description: 根据机构码获取子机构码列表
     * @Author: jiy.fang
     * @Date: 2019/7/19 15:18
     */
    public List<String> getListOrgIds(String orgId) {
        String strkey = "orgid:" + orgId;
        List<String> lists = null;
        lists = redisUtils.get(strkey, List.class);
        if (lists == null) {
            lists = new ArrayList<>();
            recursiveGetOrgId(lists, orgId);
            redisUtils.set(strkey, lists);
        }

        return lists;
    }

    //递归查询子机构
    private void recursiveGetOrgId(List<String> lists, String orgId) {
        List<String> orgIdList = organizationMapper.getOrgIdsList(orgId);
        while (orgIdList.isEmpty()) {
            return;
        }
        for (String childOrgId : orgIdList) {
            lists.add(childOrgId);
            recursiveGetOrgId(lists, childOrgId);
        }
    }

    public void resetBrcTask(String opName){
        //查询调拨任务
        List<TaskZNSDTO> tasks = znsTaskMapper.findBrcByOpName(opName);
        if(CollectionUtil.isNotEmpty(tasks)){
            List<String> lockSnList=new ArrayList<>();
            for (TaskZNSDTO dto:tasks){
                String lockSn = dto.getLockSn();
                String[] lockSns = lockSn.split("/");
                List<String> list = Arrays.asList(lockSns);
                lockSnList.addAll(list);
            }
            //去重
            if(CollectionUtil.isNotEmpty(lockSnList)){
                lockSnList=lockSnList.stream().distinct().collect(Collectors.toList());
            }

            for (String lock : lockSnList) {
                Terminal terminal = terminalMapper.getTerminalBySn(lock, TerminalTypeEnum.LOCK.getCode());
                if (ObjectUtil.isNotNull(terminal) && StrUtil.isNotBlank(terminal.getOldOrg()) && StrUtil.isNotBlank(terminal.getOrgId())) {
                    //先清除锁具在新机构中的开锁任务
                    resetTask(terminal);
                    //回退锁具
                    terminalMapper.resetLockOrg(terminal.getId());
                }
            }
        }

    }

    public void resetTask(Terminal ter) {
        //清除锁具在新机构中的开锁任务
        TaskFindBO taskFindBO=new TaskFindBO();
        taskFindBO.setOrgId(ter.getOrgId());
        taskFindBO.setLockSn(ter.getTerminalSn());
        taskFindBO.setTimeScopeBegin(ter.getStartTime());
        taskFindBO.setTimeScopeEnd(ter.getEffectTime());
        List<TaskZNSDTO> taskZNSDTOS = znsTaskMapper.selectByCon(taskFindBO);
        if(CollectionUtil.isNotEmpty(taskZNSDTOS)){
            List<String> taskIds = taskZNSDTOS.stream().map(TaskZNSDTO::getTaskId).collect(toList());
            String[] split=new String[taskIds.size()];
            split=taskIds.toArray(split);
            znsTaskMapper.updateTaskState(split);
        }
    }

}
